package com.tongji.diy.model.furniturePlacementOptimization
{
	import com.tongji.diy.model.furniturePlacementOptimization.assembleComplement.BeddingNearby;
	import com.tongji.diy.model.furniturePlacementOptimization.assembleComplement.FurnitureBase;
	import com.tongji.diy.model.furniturePlacementOptimization.assembleComplement.NearBase;
	import com.tongji.diy.model.furniturePlacementOptimization.assembleComplement.SeatNearby;
	import com.tongji.diy.model.furniturePlacementOptimization.complementStructs.PerframeIteratorData;
	import com.tongji.diy.utils.OptimizationMath;
	import com.tongji.diy.utils.PolygonMath;
	
	import flash.geom.Point;
	import flash.geom.Vector3D;
	
	import flare.loaders.Collada;
	
	//该类主要处理迭代过程
	public class ConstructorIteration
	{
		private var data:DataAndFunction = new DataAndFunction;
		
		//迭代计数器测试使用
		private const TEST_COUNT:int = 1;
		private var costComputation:CostComputing;
		
		public function ConstructorIteration(data:DataAndFunction)
		{
			this.data = data;
			
			costComputation = new CostComputing(data);
			//dispatchEvent(new IterationTestEvent(IterationTestEvent.TEST));
		}
		
		public function assignNearby():void
		{
			if(data._seatNearbyList && data._seatNearbyList.length)
			{
				collpse(heat(0),0);
			}
			
			if(data._beddingNearbyList && data._beddingNearbyList.length)
			{
				collpse(heat(1),1);	
			}
			//amendAngle();
		}
		
		//test
		public function assignNearby2(perframeData:PerframeIteratorData = null):void
		{
			if(perframeData)
			{
				if(data._seatNearbyList && data._seatNearbyList.length)
				{
					collpse2(perframeData.step,0,perframeData);
				}
				
				if(data._beddingNearbyList && data._beddingNearbyList.length)
				{
					collpse2(perframeData.step,1,perframeData);	
				}
			}
			else
			{
				if(data._seatNearbyList && data._seatNearbyList.length)
				{
					collpse2(heat(0),0,perframeData);
				}
				
				if(data._beddingNearbyList && data._beddingNearbyList.length)
				{
					collpse2(heat(1),1,perframeData);	
				}
			}
			//amendAngle();
		}
		
		private function amendAngle():void
		{
			for(var i:int = 0; data._seatNearbyList && i < data._seatNearbyList.length; ++i)
			{
				if(!data._seatNearbyList[i].anganistWall)
				{
					var angle:Number = searchMinDiffer(data._seatNearbyList[i]);
					data._seatNearbyList[i].angle = angle;
				}
			}
			
			for(i = 0; data._beddingNearbyList && i < data._beddingNearbyList.length; ++i)
			{
				if(!data._beddingNearbyList[i].anganistWall)
				{
					angle = searchMinDiffer(data._beddingNearbyList[i]);
					data._beddingNearbyList[i].angle = angle;
				}
			}
			
			function searchMinDiffer(nearby:FurnitureBase):Number
			{
				var differ:Number = Infinity;
				var angle:Number;
				for(var i:int = 0; i < data._orientedSelectionList.length; ++i)
				{
					var tempDiffer:Number = Math.abs(nearby.angle - data._orientedSelectionList[i])
					if(tempDiffer < differ)
					{
						differ = tempDiffer;
						angle = data._orientedSelectionList[i];
					}
				}
				return angle;
			}
			
		}
		
		private function heat(kindOfNearby:int):Number
		{
			//选择list
			var nearbyList:Vector.<NearBase>;
			if(kindOfNearby == 0)
				nearbyList = data._seatNearbyList;
			else
				nearbyList = data._beddingNearbyList;
			
			//存储x，y，angle值
			//			var recoder:Vector.<Vector3D> = new Vector.<Vector3D>;
			//			for(var i:int = 0; i < nearbyList.length; ++i)
			//			{
			//				recoder.push(new Vector3D(nearbyList[i].x, nearbyList[i].y, nearbyList[i].angle));
			//			}
			var collision:Boolean = true;//初始值为发生碰撞
			var step:Number = OptimizationParameter.ITERATE_INIT_STEP;
			while(collision)
			{		
				//修改初始值为不发生碰撞
				collision = false;
				
				//保证随机的家具在房间内部
				heat_inRoomRand(step, nearbyList/*,recoder*/);
				
				//碰撞检测模块
				collision = heat_collision(nearbyList);
				
				//如果发生碰撞则恢复原始值
				if(collision)
				{
					for(var i:int = 0; i < nearbyList.length; ++i)
					{
						nearbyList[i].x = data._furnitureBlock.x;//recoder[i].x;
						nearbyList[i].y = data._furnitureBlock.y;//recoder[i].y;
						nearbyList[i].angle = 0;//recoder[i].z;							
					}
					//扩大搜索范围
					step *= OptimizationParameter.ITERATE_STEP_EXPAND_RATIO;
					if(step > OptimizationParameter.HEAT_MAX_STEP)
					{
						for(var i:int = 0; i < nearbyList.length; ++i)
						{
							if(nearbyList[i].anganistWall)
							{
								var v:Vector3D = data.searchLocationWall(nearbyList as FurnitureBase,Math.random());
								nearbyList[i].x = v.x;//recoder[i].x;
								nearbyList[i].y = v.y;//recoder[i].y;
								nearbyList[i].angle = v.z;//recoder[i].z;		
							}
							else
							{
								nearbyList[i].x = data._furnitureBlock.x;//recoder[i].x;
								nearbyList[i].y = data._furnitureBlock.y;//recoder[i].y;
								nearbyList[i].angle = 0;//recoder[i].z;		
							}
						}
						trace("maybe error happend")
						return OptimizationParameter.HEAT_MAX_STEP;
					}
				}
			}
			return step;
		}
		//仅能在heat阶段使用，因为其随机化的方式是从facalblock的中心开始的
		//用于heat阶段作出随机的大概半径是合适的，但是如果放在后面的collapse函数中则会误导其随机的方法导致不能按照模拟退火的标准做法得到好的结果
		private function heat_inRoomRand(step:Number, nearbyList:Vector.<NearBase>/* recoder:Vector.<Vector3D>*/):void
		{
			//初始化随机序列
			var randNumList:Vector.<Number> = new Vector.<Number>;
			for(var i:int = 0; i < nearbyList.length; ++i)
				randNumList.push(OptimizationMath.normalRandom(), OptimizationMath.normalRandom(), OptimizationMath.normalRandom());
			
			for(i = 0; i < nearbyList.length; ++i)
			{
				if(!nearbyList[i].anganistWall)
				{
					var first:Boolean = true;
					
					while(first || !data.boundingBoxInRoom(nearbyList[i].accessibleBox,data._room))
					{
						if(!first)
						{
							randNumList[i*3] = OptimizationMath.normalRandom();
							randNumList[i*3+1] = OptimizationMath.normalRandom();
							randNumList[i*3+2] = OptimizationMath.normalRandom();
						}
						first = false;
						nearbyList[i].x = data._furnitureBlock.x + step * randNumList[3*i];
						nearbyList[i].y = data._furnitureBlock.y + step * randNumList[3*i + 1];
						nearbyList[i].angle = data._orientedSelectionList[Math.floor(Math.random()*data._orientedSelectionList.length)];
					}
				}
				else
				{
					//以下内容可能需要后期进行优化改动
					first = true;
					var tempRandNum:Number = data.reverseRandom(nearbyList[i]);
					if(tempRandNum < 0)//说明nearby当前位置不在靠墙的位置
					{
						randNumList[i*3] = OptimizationMath.randomNumNormalHandler(data.reverseRandom(data._furnitureBlock));
					}
					else
					{
						randNumList[i*3] = OptimizationMath.randomNumNormalHandler(tempRandNum);
					}
					var r:Number = randNumList[3*i];
					while(first || !data.boundingBoxInRoom(nearbyList[i].accessibleBox,data._room))
					{
						if(!first)
						{
							r = OptimizationMath.randomNumNormalHandler(randNumList[i*3]);
						}
						
						first = false;
						
						//OptimizationMath.assert(randNumList[i*2] < 1 && randNumList[i*2] >= 0);
						
						var v:Vector3D = data.searchLocationWall(nearbyList[i],r);
						
						nearbyList[i].x = v.x;
						nearbyList[i].y = v.y;
						nearbyList[i].angle = v.z;
					}
			
				}			
			}
		}
		
		private function collpse_inRoom(step:Number, nearbyList:Vector.<NearBase>, recoder:Vector.<Vector3D>):void
		{
			var randNumList:Vector.<Number> = new Vector.<Number>;
			for(var i:int = 0; i < nearbyList.length; ++i)
				randNumList.push(OptimizationMath.normalRandom(), OptimizationMath.normalRandom(), OptimizationMath.normalRandom());
			
			for(i = 0; i < nearbyList.length; ++i)
			{
				if(!nearbyList[i].anganistWall)
				{
					var first:Boolean = true;
					
					while(first || !data.boundingBoxInRoom(nearbyList[i].accessibleBox,data._room))
					{
						if(!first)
						{
							randNumList[i*3] = OptimizationMath.normalRandom();
							randNumList[i*3+1] = OptimizationMath.normalRandom();
							randNumList[i*3+2] = OptimizationMath.normalRandom();
						}
						first = false;
						nearbyList[i].x = recoder[i].x + step * randNumList[3*i];
						nearbyList[i].y = recoder[i].y + step * randNumList[3*i + 1];
						nearbyList[i].angle = data._orientedSelectionList[Math.floor(Math.random()*data._orientedSelectionList.length)];
						//nearbyList[i].angle = recoder[i].z + randNumList[3*i+2] * step / maxStep * Math.PI;		
					}
				}
				else
				{
					//以下内容可能需要后期进行优化改动
					first = true;
					var tempRandNum:Number = data.reverseRandom(nearbyList[i]);
					if(tempRandNum < 0)//说明nearby当前位置不在靠墙的位置
					{
						randNumList[i*3] = OptimizationMath.randomNumNormalHandler(data.reverseRandom(data._furnitureBlock));
					}
					else
					{
						randNumList[i*3] = OptimizationMath.randomNumNormalHandler(tempRandNum);
					}
					var r:Number = randNumList[3*i];
					while(first || !data.boundingBoxInRoom(nearbyList[i].accessibleBox,data._room))
					{
						if(!first)
						{
							r = OptimizationMath.randomNumNormalHandler(randNumList[i*3]);
						}
						
						first = false;						
						var v:Vector3D = data.searchLocationWall(nearbyList[i],r);
						
						nearbyList[i].x = v.x;
						nearbyList[i].y = v.y;
						nearbyList[i].angle = v.z;
				
					}
				}			
			}
		}
		
		
		private function heat_collision(nearbyList:Vector.<NearBase>):Boolean
		{
			var collision:Boolean = false;
			for(var i:int = 0; i < nearbyList.length; ++i)
			{
				var NBA:FurnitureBase = nearbyList[i]
				if(data.accessibleBoxCollision(NBA, data._furnitureBlock))
				{
					if(!nearbyPermeate(NBA))
					{
						return true;
					}
				}
				
				for(var j:int = i + 1; !collision && j < nearbyList.length; ++j)
				{
					var NBB:FurnitureBase = nearbyList[j];
					if(data.accessibleBoxCollision(NBA, NBB))
						return true;
				}
			}
			return false;
		}	
		
		//判断是否可以将nearby进行渗透(在组装好的facal中进行渗透尝试)，如果可以渗透则返回true，否则返回false
		private function nearbyPermeate(nearBy:FurnitureBase):Boolean
		{
			for(var i:int = 0; i < data._facalList.length; ++i)
				if(PolygonMath.rectangleSeparatingAxisCollisionTest(nearBy.accessibleBox, data._facalList[i].boundingBox) == -1)
					return false;
			
			if(data._seatList.length)
			{
				for(i = 0; i < data._seatList.length; ++i)
					if(PolygonMath.rectangleSeparatingAxisCollisionTest(nearBy.accessibleBox, data._seatList[i].accessibleBox) == -1)
						return false;
			}
			
			if(data._beddingList.length)
			{
				for(i = 0; i < data._beddingList.length; ++i)
					if(PolygonMath.rectangleSeparatingAxisCollisionTest(nearBy.accessibleBox, data._beddingList[i].accessibleBox) == -1)
						return false;
			}
			return true;
		}
		
		private function collpse(step:Number,kindOfNearby:int):void
		{
			var nearbyList:Vector.<NearBase>;
			if(kindOfNearby == 0)
				nearbyList = data._seatNearbyList;
			else
				nearbyList = data._beddingNearbyList;
			//进一步扩大搜索半径
			step *= OptimizationParameter.COLLPSE_PROC_EXPAND_TIMES;
			//记录_seatlist中家具的坐标初始值，z坐标记录angle
			var recorder:Vector.<Vector3D> = new Vector.<Vector3D>;
			//记录初始的状态
			data._cost = 0;
			for(var i:int = 0; i < nearbyList.length; ++i)
			{
				data._cost += costComputation.cost_distance(nearbyList[i]);
				data._cost += costComputation.cost_angle(nearbyList[k]);
				recorder.push(new Vector3D(nearbyList[i].x, nearbyList[i].y, nearbyList[i].angle));	
			}
			data._cost += costComputation.cost_symmetry();
			//主循环
			var tempCost:Number = data._cost;
			var count:int = 0;
			var Tcount:int = 1;
			var T:int = OptimizationParameter.INIT_TEMPETURE * Math.log(nearbyList.length + Math.E - 1) ;
			var j:int = 0;
			//用于在随机过程中无法找到合适的布局时退出循环使用
			var noAccessibleLayout:Boolean = false;
			var iterationCount:int = 0;
			while(T > 1 && !noAccessibleLayout )
			{
				while(j < T && !noAccessibleLayout)
				{
					++ iterationCount;
					if(reAssign(step,nearbyList,recorder) > OptimizationParameter.COLLISION_TEMINITE_TIMES)
						noAccessibleLayout = true;
					
					//计算重新分配以后的代价
					tempCost = 0;
					var tempRecoder:Vector.<Vector3D> = new Vector.<Vector3D>;
					for(var k:int = 0; k < nearbyList.length; ++k)
					{
						tempCost += costComputation.cost_distance(nearbyList[k]);
						tempCost += costComputation.cost_angle(nearbyList[k]);
						tempRecoder.push(new Vector3D(nearbyList[k].x, nearbyList[k].y, nearbyList[k].angle));
					}
					tempCost += costComputation.cost_symmetry();
					
					if(tempCost < data._cost)
					{
						data._cost = tempCost;
						recorder = tempRecoder;
					}
					else
					{
						//与标准模拟退火算法相比替换了函数，该函数是选用y = 1/e^x这个函数，
						//选取目的是f(0)=1,f(infinite)=0,f(x)在0到正无穷积分为1；
						//var p:Number = 1/Math.exp(-(data._cost - tempCost));
						var p:Number = 1/Math.exp((tempCost - data._cost)/ (T*0.1));
						if(Math.random() < p)
						{
							data._cost = tempCost;
							recorder = tempRecoder;
						}
					}
					
					++j;
				}
				
				j = 0;
				T = T*0.8;
				Tcount++;
				step *= OptimizationParameter.COLLPSE_PROC_DECREASE_RATE;
				
				for(i = 0; i < nearbyList.length; ++i)
				{
					nearbyList[i].x = recorder[i].x;
					nearbyList[i].y = recorder[i].y;
					nearbyList[i].angle = recorder[i].z
				}
			}
			
			trace("iterationTimes",iterationCount);
			for(i = 0; i < nearbyList.length; ++i)
			{
				nearbyList[i].x = recorder[i].x;
				nearbyList[i].y = recorder[i].y;
				nearbyList[i].angle = recorder[i].z
			}
		}
		
		
		private function collpse2(step:Number,kindOfNearby:int, perFrameData:PerframeIteratorData = null):void
		{
			if(!perFrameData)
			{
				var nearbyList:Vector.<NearBase>;
				if(kindOfNearby == 0)
					nearbyList = data._seatNearbyList;
				else
					nearbyList = data._beddingNearbyList;
				//进一步扩大搜索半径
				step *= OptimizationParameter.COLLPSE_PROC_EXPAND_TIMES;
				//记录_seatlist中家具的坐标初始值，z坐标记录angle
				var recorder:Vector.<Vector3D> = new Vector.<Vector3D>;
				//记录初始的状态
				data._cost = 0;
				for(var i:int = 0; i < nearbyList.length; ++i)
				{
					data._cost += costComputation.cost_distance(nearbyList[i]);
					data._cost += costComputation.cost_angle(nearbyList[k]);
					recorder.push(new Vector3D(nearbyList[i].x, nearbyList[i].y, nearbyList[i].angle));				
				}	
				data._cost += costComputation.cost_symmetry();
				//data._cost += costComputation.cost_symmetry();
				//主循环
				var tempCost:Number = data._cost;
				var count:int = 0;
				var Tcount:int = 1;
				var T:int = OptimizationParameter.INIT_TEMPETURE * Math.log(nearbyList.length + Math.E - 1) ;
				var j:int = 0;
			}
			else
			{
				T = perFrameData.T;
				recorder = perFrameData.recorder;
				j = perFrameData.index;
				nearbyList = perFrameData.nearbylist;	
				step = perFrameData.step;
				data._cost = perFrameData.cost;
				Tcount = perFrameData.Tcount;
				count = perFrameData.count;
			}
			
			//用于在随机过程中无法找到合适的布局时退出循环使用
			var noAccessibleLayout:Boolean = false;
			while(T > 1 && !noAccessibleLayout)
			{
				while(j < T && !noAccessibleLayout)
				{
					if(reAssign(step,nearbyList,recorder) > OptimizationParameter.COLLISION_TEMINITE_TIMES)
						noAccessibleLayout = true;
					
					//计算重新分配以后的代价
					tempCost = 0;
					var tempRecoder:Vector.<Vector3D> = new Vector.<Vector3D>;
					var symmteryCost:Number = 0;
					for(var k:int = 0; k < nearbyList.length; ++k)
					{
						tempCost += costComputation.cost_distance(nearbyList[k]);
						tempCost += costComputation.cost_angle(nearbyList[k]);
						tempRecoder.push(new Vector3D(nearbyList[k].x, nearbyList[k].y, nearbyList[k].angle));
					}
					tempCost += costComputation.cost_symmetry();
					
					if(tempCost < data._cost)
					{
						data._cost = tempCost;
						recorder = tempRecoder;
					}
					else
					{
						//与标准模拟退火算法相比替换了函数，该函数是选用y = 1/e^x这个函数，
						//选取目的是f(0)=1,f(infinite)=0,f(x)在0到正无穷积分为1；
						//var p:Number = 1/Math.exp(-(data._cost - tempCost));
						var p:Number = 1/Math.exp((tempCost - data._cost)/ (T*0.1));
						if(Math.random() < p)
						{
							data._cost = tempCost;
							recorder = tempRecoder;
						}
					}
					
					++j;
					//----test
					if(!(j % TEST_COUNT))
					{
						data.perFrameData.used = true;
						data.perFrameData.index = j;
						data.perFrameData.T = T;
						data.perFrameData.recorder = recorder;
						data.perFrameData.nearbylist = nearbyList;
						data.perFrameData.step = step;
						data.perFrameData.cost = data._cost;
						data.perFrameData.Tcount = Tcount;
						data.perFrameData.count = count;
						return;
					}
				}
				
				j = 0;
				T = T*0.8;
				Tcount++;
				step *= OptimizationParameter.COLLPSE_PROC_DECREASE_RATE;
				
				for(i = 0; i < nearbyList.length; ++i)
				{
					nearbyList[i].x = recorder[i].x;
					nearbyList[i].y = recorder[i].y;
					nearbyList[i].angle = recorder[i].z
				}
			}
			
			for(i = 0; i < nearbyList.length; ++i)
			{
				nearbyList[i].x = recorder[i].x;
				nearbyList[i].y = recorder[i].y;
				nearbyList[i].angle = recorder[i].z
			}
		}
		
		private function reAssign(step:Number,nearbyList:Vector.<NearBase>,recoder:Vector.<Vector3D>):int
		{
			var collision:Boolean = true;
			var collisionCount:int = 0;
			
			while(collision)
			{				
				//修改初始值为不发生碰撞
				collision = false;
				var visible:Boolean = true;
				//保证随机的家具在房间内部
				collpse_inRoom(step,nearbyList,recoder);
				//error：heat_inRoomRand(step,nearbyList,recoder);
				
				//碰撞检测模块
				collision = heat_collision(nearbyList)
				
				//可见性测试
				visible = data.visibleTest();	
				
				//如果发生碰撞则恢复原始值
				if(collision || !visible)
				{
					for(var i:int = 0; i < nearbyList.length; ++i)
					{
						nearbyList[i].x = recoder[i].x;
						nearbyList[i].y = recoder[i].y;
						nearbyList[i].angle = recoder[i].z;//randNumList[3*i+2] * step / maxStep * Math.PI;
					}
				}
				
				++ collisionCount;
				if(collisionCount > OptimizationParameter.COLLISION_TEMINITE_TIMES)
					return collisionCount;
			}
			
			return collisionCount;
		}
		
	}
}